1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # POS Membership module for OpenERP, Manage membership payments from POS.
5 # Copyright (C) 2013 L'Heureux Cyclage (<http://www.heureux-cyclage.org>)
7 # This file is a part of POS Membership
9 # POS Membership is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # POS Membership is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ##############################################################################
23 from openerp
import netsvc
24 from openerp
.osv
import fields
, osv
25 from openerp
.tools
.translate
import _
27 from datetime
import datetime
, date
28 from dateutil
.relativedelta
import relativedelta
31 ('none', 'Non Member'),
32 ('canceled', 'Cancelled Member'),
33 ('old', 'Old Member'),
34 ('waiting', 'Waiting Member'),
35 ('invoiced', 'Invoiced Member'),
36 ('free', 'Free Member'),
37 ('paid', 'Paid Member'),
41 class pos_session(osv
.osv
):
42 _inherit
= 'pos.session'
44 def open_cb(self
, cr
, uid
, ids
, context
=None):
46 Avoid call the Point Of Sale interface and set the pos.session to 'opened' (in progress)
51 if isinstance(ids
, (int, long)):
54 this_record
= self
.browse(cr
, uid
, ids
[0], context
=context
)
55 this_record
._workflow
_signal
('open')
57 context
.update(active_id
=this_record
.id)
65 class pos_order(osv
.osv
):
66 _inherit
= 'pos.order'
68 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
70 partner_obj
= self
.pool
.get('res.partner')
71 for tmp_partner
in partners
:
72 partner
= tmp_partner
['data']
73 partner_id
= partner_obj
.create(cr
, uid
, {
74 'name': partner
['name'],
76 partner_ids
.append(partner_id
)
77 #self.signal_paid(cr, uid, [partner_id])
80 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
81 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
82 #_logger.info("orders: %r", orders)
84 for tmp_order
in orders
:
85 order
= tmp_order
['data']
86 order_id
= self
.create(cr
, uid
, {
87 'name': order
['name'],
88 'user_id': order
['user_id'] or False,
89 'session_id': order
['pos_session_id'],
90 'lines': order
['lines'],
91 'pos_reference': order
['name'],
92 #-- BEGIN pos_membership
93 'partner_id': order
['partner_id'],
94 #-- END pos_membership
97 for payments
in order
['statement_ids']:
99 self
.add_payment(cr
, uid
, order_id
, {
100 'amount': payment
['amount'] or 0.0,
101 'payment_date': payment
['name'],
102 'statement_id': payment
['statement_id'],
103 'payment_name': payment
.get('note', False),
104 'journal': payment
['journal_id']
107 if order
['amount_return']:
108 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
109 cash_journal
= session
.cash_journal_id
110 cash_statement
= False
112 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type == 'cash', session
.statement_ids
)
113 if not len(cash_journal_ids
):
114 raise osv
.except_osv(_('error!'),
115 _("No cash statement found for this session. Unable to record returned cash."))
116 cash_journal
= cash_journal_ids
[0].journal_id
117 self
.add_payment(cr
, uid
, order_id
, {
118 'amount': -order
['amount_return'],
119 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
120 'payment_name': _('return'),
121 'journal': cash_journal
.id,
123 order_ids
.append(order_id
)
124 wf_service
= netsvc
.LocalService("workflow")
125 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
131 class membership_line(osv
.osv
):
133 _inherit
= 'membership.membership_line'
135 def _get_partners(self
, cr
, uid
, ids
, context
=None):
136 list_membership_line
= []
137 member_line_obj
= self
.pool
.get('membership.membership_line')
138 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
139 if partner
.member_lines
:
140 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [l
.id for l
in partner
.member_lines
])], context
=context
)
141 return list_membership_line
143 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
144 # list_membership_line = []
145 # member_line_obj = self.pool.get('membership.membership_line')
146 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
147 # if invoice.invoice_line:
148 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
150 # { 'class': 'account.invoice'
151 # , 'ids': list_membership_line
153 # #res= list_membership_line
154 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
156 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
157 list_membership_line
= []
158 member_line_obj
= self
.pool
.get('membership.membership_line')
159 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
161 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [l
.id for l
in order
.lines
])], context
=context
)
163 # { 'class': 'pos.order'
164 # , 'ids': list_membership_line
166 res
= list_membership_line
169 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
170 """Check if membership product is not in the past
171 @param self: The object pointer
172 @param cr: the current row, from the database cursor,
173 @param uid: the current user’s ID for security checks,
174 @param ids: List of Membership Line IDs
175 @param context: A standard dictionary for contextual values
179 SELECT MIN(ml.date_to - ai.date_invoice)
180 FROM membership_membership_line ml
181 JOIN account_invoice_line ail ON (
182 ml.account_invoice_line = ail.id
184 JOIN account_invoice ai ON (
185 ai.id = ail.invoice_id)
186 WHERE ml.id IN %s''', (tuple(ids
),))
189 if r
[0] and r
[0] < 0:
192 SELECT MIN(ml.date_to - ai.date_order)
193 FROM membership_membership_line ml
194 JOIN pos_order_line ail ON (
195 ml.pos_order_line = ail.id
197 JOIN pos_order ai ON (
198 ai.id = ail.order_id)
199 WHERE ml.id IN %s''', (tuple(ids
),))
202 if r
[0] and r
[0] < 0:
206 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
207 """Compute the state lines
208 @param self: The object pointer
209 @param cr: the current row, from the database cursor,
210 @param uid: the current user’s ID for security checks,
211 @param ids: List of Membership Line IDs
212 @param name: Field Name
213 @param context: A standard dictionary for contextual values
214 @param return: Dictionary of state Value
217 inv_obj
= self
.pool
.get('account.invoice')
218 ord_obj
= self
.pool
.get('pos.order')
219 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
221 SELECT i.state, i.id FROM
225 SELECT l.invoice_id FROM
226 account_invoice_line l WHERE
228 SELECT ml.account_invoice_line FROM
229 membership_membership_line ml WHERE
234 fetched
= cr
.fetchone()
238 if (istate
== 'draft') |
(istate
== 'proforma'):
240 elif istate
== 'open':
242 elif istate
== 'paid':
244 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
245 for payment
in inv
.payment_ids
:
246 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
248 elif istate
== 'cancel':
253 SELECT i.state, i.id FROM
257 SELECT l.order_id FROM
258 pos_order_line l WHERE
260 SELECT ml.pos_order_line FROM
261 membership_membership_line ml WHERE
266 fetched
= cr
.fetchone()
268 res
[line
.id] = 'canceled'
270 self
.write(cr
, uid
, line
.id, {'partner': line
.partner
.id})
271 # NOTE: force une mise à jour du partner,
272 # car il n'y en a pas lors de la création du pos.order
273 # dans le PoS (pour le moment)
274 partner_obj
= self
.pool
.get('res.partner')
275 for partner
in partner_obj
.browse(cr
, uid
, [line
.partner
.id], context
=context
):
276 if not partner
.member_ident
:
277 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
278 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
281 if (ostate
== 'paid') |
(ostate
== 'draft'):
283 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
285 # XXX: regarder l'équivalent de out_refund pour un pos.order
286 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
287 #for payment in inv.payment_ids:
288 # if payment.invoice and payment.invoice.type == 'out_refund':
290 elif ostate
== 'cancel':
295 def write(self
, cr
, uid
, ids
, vals
, context
=None):
296 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
299 def create(self
, cr
, uid
, vals
, context
=None):
300 member_line_obj
= self
.pool
.get('membership.membership_line')
301 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
305 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
306 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
307 'state': fields
.function(_state
,
308 string
='Membership Status', type='selection',
311 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
312 # NOTE: déjà géré par membership.membership_line._get_membership_lines
313 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
314 'res.partner': (_get_partners
, ['membership_state'], 12),
315 }, help="""It indicates the membership status.
316 -Non Member: A member who has not applied for any membership.
317 -Cancelled Member: A member who has cancelled his membership.
318 -Old Member: A member whose membership date has expired.
319 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
320 -Invoiced Member: A member whose invoice has been created.
321 -Paid Member: A member who has paid the membership amount."""),
322 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
323 # XXX: pos_order_line a aussi un company_id
329 class Partner(osv
.osv
):
331 _inherit
= 'res.partner'
333 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
334 member_line_obj
= self
.pool
.get('membership.membership_line')
335 res_obj
= self
.pool
.get('res.partner')
336 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
338 for data
in data_inv
:
339 list_partner
.append(data
.partner
.id)
342 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
346 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
347 inv_obj
= self
.pool
.get('account.invoice')
348 res_obj
= self
.pool
.get('res.partner')
349 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
351 for data
in data_inv
:
352 list_partner
.append(data
.partner_id
.id)
355 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
359 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
360 ord_obj
= self
.pool
.get('pos.order')
361 res_obj
= self
.pool
.get('res.partner')
362 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
364 for data
in data_ord
:
365 list_partner
.append(data
.partner_id
.id)
368 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
372 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
373 """This Function return Membership State For Given Partner.
374 @param self: The object pointer
375 @param cr: the current row, from the database cursor,
376 @param uid: the current user’s ID for security checks,
377 @param ids: List of Partner IDs
378 @param name: Field Name
379 @param context: A standard dictionary for contextual values
380 @param return: Dictionary of Membership state Value
385 today
= time
.strftime('%Y-%m-%d')
387 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
388 if not partner_data
.free_member
:
389 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
392 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
396 if partner_data
.member_lines
:
397 for mline
in partner_data
.member_lines
:
398 if mline
.date_to
>= today
:
399 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
400 istate
= mline
.account_invoice_line
.invoice_id
.state
403 inv
= mline
.account_invoice_line
.invoice_id
404 for payment
in inv
.payment_ids
:
405 if payment
.invoice
.type == 'out_refund':
408 elif istate
== 'open' and s
!= 0:
410 elif istate
== 'cancel' and s
!= 0 and s
!= 1:
412 elif (istate
== 'draft' or istate
== 'proforma') and s
!= 0 and s
!= 1:
414 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
415 ostate
= mline
.pos_order_line
.order_id
.state
416 if ostate
== 'paid' and s
!= 0 and s
!= 1:
418 if ostate
== 'invoiced':
422 # XXX: regarder l'équivalent de out_refund pour un pos.order
423 #inv = mline.pos_order_line.order_id
424 #for payment in inv.payment_ids:
425 # if payment.invoice.type == 'out_refund':
428 elif ostate
== 'open' and s
!= 0:
429 # XXX: 1 donne invoiced, c'est pitet pas bon
431 elif ostate
== 'cancel' and s
!= 0 and s
!= 1:
433 elif ostate
== 'draft' and s
!= 0 and s
!= 1:
436 for mline
in partner_data
.member_lines
:
437 if mline
.date_from
< today
and \
438 mline
.date_to
< today
and \
439 mline
.date_from
<= mline
.date_to
and \
440 ((mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
441 (mline
.pos_order_line
and \
442 (mline
.pos_order_line
.order_id
.state
== 'paid' or \
443 mline
.pos_order_line
.order_id
.state
== 'done' or \
444 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
450 # special case when the partner is imported from a file,
451 # in this case is has a valid membership lines but
452 # no payment information associated, consider it valid
454 no_payment_info_at_all
= True
457 for mline
in partner_data
.member_lines
:
458 if mline
.date_to
>= today
:
461 if mline
.account_invoice_line
or mline
.pos_order_line
:
462 no_payment_info_at_all
= False
464 if no_payment_info_at_all
and valid_line
:
479 if partner_data
.free_member
and s
!= 0:
483 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
484 """Return date of membership"""
487 member_line_obj
= self
.pool
.get('membership.membership_line')
488 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
489 partner_id
= partner
.id
491 'membership_start': False,
492 'membership_stop': False,
493 'membership_cancel': False
495 if name
== 'membership_start':
496 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
497 limit
=1, order
='date_from', context
=context
)
499 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
500 ['date_from'], context
=context
)['date_from']
502 if name
== 'membership_stop':
503 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
504 limit
=1, order
='date_to desc', context
=context
)
506 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
507 ['date_to'], context
=context
)['date_to']
509 if name
== 'membership_cancel':
510 if partner
.membership_state
== 'canceled':
511 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
513 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
516 def _get_partners(self
, cr
, uid
, ids
, context
=None):
519 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
523 def __get_membership_state(self
, *args
, **kwargs
):
524 return self
._membership
_state
(*args
, **kwargs
)
527 'membership_state': fields
.function(
528 __get_membership_state
,
529 string
= 'Current Membership Status', type = 'selection',
532 # NOTE: il est important que la priorité soit plus grande
533 # que les membership_{start,stop,cancel}
534 # car _membership_state s'en sert et doit donc les trouver à jour.
535 'account.invoice': (_get_invoice_partner
, ['state'], 20),
536 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
537 'membership.membership_line': (_get_partner_id
, ['state'], 20),
538 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
539 }, help="""It indicates the membership state.
540 -Non Member: A partner who has not applied for any membership.
541 -Cancelled Member: A member who has cancelled his membership.
542 -Old Member: A member whose membership date has expired.
543 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
544 -Invoiced Member: A member whose invoice has been created.
545 -Paying member: A member who has paid the membership fee."""),
546 'membership_start': fields
.function(
547 _membership_date
, multi
= 'membership_start',
548 string
= 'Membership Start Date', type = 'date',
550 'account.invoice': (_get_invoice_partner
, ['state'], 10),
551 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
552 'membership.membership_line': (_get_partner_id
, ['state'], 10),
553 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
554 }, help="Date from which membership becomes active."),
555 'membership_stop': fields
.function(
557 string
= 'Membership End Date', type='date', multi
='membership_stop',
559 'account.invoice': (_get_invoice_partner
, ['state'], 10),
560 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
561 'membership.membership_line': (_get_partner_id
, ['state'], 10),
562 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
563 }, help="Date until which membership remains active."),
564 'membership_cancel': fields
.function(
566 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
568 'account.invoice': (_get_invoice_partner
, ['state'], 11),
569 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
570 'membership.membership_line': (_get_partner_id
, ['state'], 10),
571 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
572 }, help="Date on which membership has been cancelled"),
577 class pos_order(osv
.osv
):
578 _inherit
= 'pos.order'
580 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
581 def action_invoice(self
, cr
, uid
, ids
, context
=None):
582 wf_service
= netsvc
.LocalService("workflow")
583 inv_ref
= self
.pool
.get('account.invoice')
584 inv_line_ref
= self
.pool
.get('account.invoice.line')
585 product_obj
= self
.pool
.get('product.product')
588 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
590 inv_ids
.append(order
.invoice_id
.id)
593 if not order
.partner_id
:
594 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
596 acc
= order
.partner_id
.property_account_receivable
.id
597 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
600 'origin': order
.name
,
602 'journal_id': order
.sale_journal
.id or None,
603 'type': 'out_invoice',
604 'reference': order
.name
,
605 'partner_id': order
.partner_id
.id,
606 'comment': order
.note
or '',
607 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
610 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
611 if not inv
.get('account_id', None):
612 inv
['account_id'] = acc
613 for line
in order
.lines
:
615 #'invoice_id': inv_id,
616 'product_id': line
.product_id
.id,
617 'quantity': line
.qty
,
619 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
620 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
622 line
.product_id
.uom_id
.id,
623 line
.qty
, partner_id
= order
.partner_id
.id,
624 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
625 if line
.product_id
.description_sale
:
626 inv_line
['note'] = line
.product_id
.description_sale
627 inv_line
['price_unit'] = line
.price_unit
628 inv_line
['discount'] = line
.discount
629 inv_line
['name'] = inv_name
630 inv_line
['invoice_line_tax_id'] = [(6, 0, [x
.id for x
in line
.product_id
.taxes_id
] )]
631 inv_line_ref
.create(cr
, uid
, inv_line
, context
=context
)
632 #inv_line_ref.create(cr, uid, inv_line, context=context)
633 inv
['invoice_line'].append((0, 0, inv_line
))
634 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
636 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
637 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
638 inv_ids
.append(inv_id
)
639 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
640 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
642 if not inv_ids
: return {}
644 mod_obj
= self
.pool
.get('ir.model.data')
645 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
646 res_id
= res
and res
[1] or False
648 'name': _('Customer Invoice'),
652 'res_model': 'account.invoice',
653 'context': "{'type':'out_invoice'}",
654 'type': 'ir.actions.act_window',
657 'res_id': inv_ids
and inv_ids
[0] or False,
660 def write(self
, cr
, uid
, ids
, vals
, context
=None):
661 pos_order_obj
= self
.pool
.get('pos.order')
662 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
665 def create(self
, cr
, uid
, vals
, context
=None):
666 pos_order_obj
= self
.pool
.get('pos.order')
667 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
670 def onchange_partner_id(self
, cr
, uid
, ids
, part
=False, context
=None):
672 - Change membership stop value if partner change
673 - Change partner in membership line if s·he is change
677 res
= super(pos_order
, self
).onchange_partner_id(cr
, uid
, ids
, part
=part
, context
=context
)
678 membership_stop
= self
.pool
.get('res.partner').browse(cr
, uid
, part
, context
=context
).membership_stop
679 res
['value']['membership_stop'] = membership_stop
680 ml_line_obj
= self
.pool
.get('membership.membership_line')
681 pol_obj
= self
.pool
.get('pos.order.line')
683 pol_ids
= pol_obj
.search(cr
, uid
, [('order_id', '=', id)], context
=context
)
684 pols
= pol_obj
.browse(cr
, uid
, pol_ids
, context
=context
)
686 if pol
.product_id
.membership
:
687 ml_line_ids
= ml_line_obj
.search(cr
, uid
, [('pos_order_line', '=', pol
.id)], context
=context
)
688 ml_line_obj
.write(cr
, uid
, ml_line_ids
, {'partner': part
}, context
=context
)
691 def _get_membership_stop(self
, cr
, uid
, ids
, name
, args
, context
=None):
692 """This function return the end date of the partner in pos order."""
694 for order
in self
.browse(cr
, uid
, ids
):
695 res
[order
.id] = order
.partner_id
.membership_stop
699 'membership_stop': fields
.function(
700 _get_membership_stop
,
701 string
='Membership stop',
703 help='The end date of the last membership of this partner.',
708 class pos_order_line(osv
.osv
):
709 _inherit
= 'pos.order.line'
711 def write(self
, cr
, uid
, ids
, vals
, context
=None):
712 member_line_obj
= self
.pool
.get('membership.membership_line')
713 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
714 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
715 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
716 if line
.product_id
and line
.product_id
.membership
:
717 member_line_id
= member_line_obj
.search(cr
, uid
718 , [('partner', '=', line
.order_id
.partner_id
.id)
719 ,('pos_order_line', '=', line
.id)]
722 for member_line
in member_line_obj
.browse(cr
, uid
, member_line_id
, context
=context
):
723 # NOTE: get member_line created in pos_membership.pos_order_line.create
724 date_from
= member_line
.date_from
725 date_to
= member_line
.date_to
726 if line
.product_id
.membership_date2date
:
727 date_from
= datetime
.strptime(line
.order_id
.date_order
, "%Y-%m-%d %H:%M:%S")
728 date_to
= date_from
+ relativedelta(months
=+12, days
=-1) # TODO: parameterize this delta?
729 date_from
= date_from
.strftime("%Y-%m-%d")
730 date_to
= date_to
.strftime("%Y-%m-%d")
731 member_line_obj
.write(cr
, uid
, member_line
.id, {
732 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
733 'membership_id': line
.product_id
.id,
734 'member_price': line
.price_unit
,
736 'date_from': date_from
,
738 'pos_order_line': line
.id,
741 if line
.product_id
.membership_grouped
:
742 if line
.order_id
.partner_id
.associate_members
:
743 associate_member_line_ids
= member_line_obj
.search(cr
, uid
744 , [ ('pos_order_line', '=', line
.id)
745 , ('partner', '!=', line
.order_id
.partner_id
.id)
748 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
749 member_line_obj
.write(cr
, uid
, associate_member_line
.id
750 , {'date_from': date_from
755 print("DEV: mettre une contrainte pour l'objet\
756 membership.membership_line interdisant les\
757 adhésions groupées reliées à des partenaires\
758 sans membres associés")
760 associate_member_line_ids
= member_line_obj
.search(cr
, uid
761 , [ ('pos_order_line', '=', line
.id)
762 , ('partner', '!=', line
.order_id
.partner_id
.id)
765 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
766 #Define member ident if it's necessary
767 partners
= [line
.order_id
.partner_id
]
768 if line
.order_id
.partner_id
.associate_members
:
769 partners
.extend(line
.order_id
.partner_id
.associate_members
)
771 if not i
.member_ident
:
772 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
773 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
774 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
775 # Product line has changed to a non membership product
776 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
779 def unlink(self
, cr
, uid
, ids
, context
=None):
780 """Remove Membership Line Record for Account Invoice Line
782 member_line_obj
= self
.pool
.get('membership.membership_line')
784 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
785 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
786 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
788 def create(self
, cr
, uid
, vals
, context
=None):
789 member_line_obj
= self
.pool
.get('membership.membership_line')
790 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
791 line
= self
.browse(cr
, uid
, res
, context
=context
)
793 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
794 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
795 date_from
= line
.product_id
.membership_date_from
796 date_to
= line
.product_id
.membership_date_to
797 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
798 date_from
= line
.order_id
.date_order
799 if line
.product_id
.membership_date2date
:
800 date_from
= datetime
.strptime(line
.order_id
.date_order
, "%Y-%m-%d %H:%M:%S")
801 date_to
= date_from
+ relativedelta(months
=+12, days
=-1) # TODO: parameterize this delta?
802 date_from
= date_from
.strftime("%Y-%m-%d")
803 date_to
= date_to
.strftime("%Y-%m-%d")
804 member_line_obj
.create(cr
, uid
, {
805 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
806 'membership_id': line
.product_id
.id,
807 'member_price': line
.price_unit
,
809 'date_from': date_from
,
811 'pos_order_line': line
.id,
813 partners
= [line
.order_id
.partner_id
]
814 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
815 partners
.extend(line
.order_id
.partner_id
.associate_members
)
816 #Adding membership lines just for associate partners
817 for associate_member
in line
.order_id
.partner_id
.associate_members
:
818 member_line_obj
.create(cr
, uid
, {
819 'partner': associate_member
.id,
820 'membership_id': line
.product_id
.id,
821 'member_price': line
.price_unit
,
822 'date': time
.strftime('%Y-%m-%d'),
823 'date_from': date_from
,
825 'pos_order_line': line
.id,
827 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
828 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
829 #Define member ident if it's necessary
833 if not i
.member_ident
:
834 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
835 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
840 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: